package com.bolt.common.crypto;


import com.bolt.common.crypto.digest.HMac;
import com.bolt.common.crypto.digest.HmacAlgorithm;
import com.bolt.common.crypto.digest.SM3Digest;
import com.bolt.common.crypto.digest.mac.BCHMacEngine;
import com.bolt.common.crypto.digest.mac.MacEngine;
import org.bouncycastle.crypto.params.ECDomainParameters;

/**
 * SM国密算法工具类<br>
 * 此工具类依赖org.bouncycastle:bcprov-jdk15to18
 * <p>
 * <p>封装包括：</p>
 * <ul>
 * <li>SM2 椭圆曲线非对称加密和签名</li>
 * <li>SM3 杂凑算法</li>
 * <li>SM4 对称加密</li>
 * </ul>
 */
public class SmUtil {

    private final static int RS_LEN = 32;
    /**
     * SM2默认曲线
     */
    public static final String SM2_CURVE_NAME = "sm2p256v1";


    /**
     * bc加解密使用旧标c1||c2||c3，此方法在加密后调用，将结果转化为c1||c3||c2
     *
     * @param c1c2c3             加密后的bytes，顺序为C1C2C3
     * @param ecDomainParameters {@link ECDomainParameters}
     * @return 加密后的bytes，顺序为C1C3C2
     */
    public static byte[] changeC1C2C3ToC1C3C2(byte[] c1c2c3, ECDomainParameters ecDomainParameters) {
        // sm2p256v1的这个固定65。可看GMNamedCurves、ECCurve代码。
        final int c1Len = (ecDomainParameters.getCurve().getFieldSize() + 7) / 8 * 2 + 1;
        final int c3Len = 32; // new SM3Digest().getDigestSize();
        byte[] result = new byte[c1c2c3.length];
        System.arraycopy(c1c2c3, 0, result, 0, c1Len); // c1
        System.arraycopy(c1c2c3, c1c2c3.length - c3Len, result, c1Len, c3Len); // c3
        System.arraycopy(c1c2c3, c1Len, result, c1Len + c3Len, c1c2c3.length - c1Len - c3Len); // c2
        return result;
    }

    /**
     * bc加解密使用旧标c1||c3||c2，此方法在解密前调用，将密文转化为c1||c2||c3再去解密
     *
     * @param c1c3c2             加密后的bytes，顺序为C1C3C2
     * @param ecDomainParameters {@link ECDomainParameters}
     * @return c1c2c3 加密后的bytes，顺序为C1C2C3
     */
    public static byte[] changeC1C3C2ToC1C2C3(byte[] c1c3c2, ECDomainParameters ecDomainParameters) {
        // sm2p256v1的这个固定65。可看GMNamedCurves、ECCurve代码。
        final int c1Len = (ecDomainParameters.getCurve().getFieldSize() + 7) / 8 * 2 + 1;
        final int c3Len = 32; // new SM3Digest().getDigestSize();
        byte[] result = new byte[c1c3c2.length];
        System.arraycopy(c1c3c2, 0, result, 0, c1Len); // c1: 0->65
        System.arraycopy(c1c3c2, c1Len + c3Len, result, c1Len, c1c3c2.length - c1Len - c3Len); // c2
        System.arraycopy(c1c3c2, c1Len, result, c1c3c2.length - c3Len, c3Len); // c3
        return result;
    }


    /**
     * HmacSM3算法实现
     *
     * @param key 密钥
     * @return {@link HMac} 对象，调用digestXXX即可
     */
    public static HMac hmacSm3(byte[] key) {
        return new HMac(HmacAlgorithm.HmacSM3, key);
    }

    /**
     * 创建HmacSM3算法的{@link MacEngine}
     *
     * @param key 密钥
     * @return {@link MacEngine}
     * @since 4.5.13
     */
    public static MacEngine createHmacSm3Engine(byte[] key) {
        return new BCHMacEngine(new SM3Digest(), key);
    }
}
